{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "reported-split",
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.preprocessing.image import load_img, img_to_array\n",
    "from pathlib import Path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "improved-bacteria",
   "metadata": {},
   "outputs": [],
   "source": [
    "current_dir = Path.cwd()\n",
    "target_image_path = str(current_dir) + '\\Desktop\\TF\\Manjaro.jpg'\n",
    "style_reference_image_path = str(current_dir) + '\\Desktop\\TF\\Starry-Night-vr-Background.jpg'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "taken-hamilton",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "C:\\Users\\123\n"
     ]
    }
   ],
   "source": [
    "print(current_dir)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "chronic-brick",
   "metadata": {},
   "outputs": [],
   "source": [
    "width, height = load_img(target_image_path).size\n",
    "img_height = 400\n",
    "img_width = int(width * img_height / height)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "dramatic-information",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from keras.applications import vgg19"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "composed-drinking",
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess_image(image_path):\n",
    "    img = load_img(image_path, target_size=(img_height, img_width))\n",
    "    img = img_to_array(img)\n",
    "    img = np.expand_dims(img, axis=0)\n",
    "    img = vgg19.preprocess_input(img)\n",
    "    return img\n",
    "\n",
    "def deprocess_image(x):\n",
    "    x[:,:,0] += 103.939\n",
    "    x[:,:,1] += 116.779\n",
    "    x[:,:,2] += 123.68 \n",
    "    x = x[:,:, ::-1]\n",
    "    x = np.clip(x,0,255).astype('uint8')\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "electoral-surgery",
   "metadata": {},
   "outputs": [],
   "source": [
    "#from keras import backend as K\n",
    "from tensorflow.keras import backend as K\n",
    "import tensorflow as tf\n",
    "tf.compat.v1.disable_eager_execution()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "spread-blackberry",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model loaded.\n"
     ]
    }
   ],
   "source": [
    "target_image = K.constant(preprocess_image(target_image_path))\n",
    "style_reference_image = K.constant(preprocess_image(style_reference_image_path))\n",
    "combination_image = K.placeholder((1, img_height, img_width, 3))\n",
    "input_tensor = K.concatenate([target_image, style_reference_image, combination_image], axis=0)\n",
    "\n",
    "model = vgg19.VGG19(input_tensor=input_tensor, weights='imagenet', include_top=False)\n",
    "print('Model loaded.')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "elder-cleanup",
   "metadata": {},
   "outputs": [],
   "source": [
    "def content_loss(base, combination):\n",
    "    return K.sum(K.square(combination - base))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "treated-genealogy",
   "metadata": {},
   "outputs": [],
   "source": [
    "def gram_matrix(x):\n",
    "    features = K.batch_flatten(K.permute_dimensions(x, (2,0,1)))\n",
    "    gram = K.dot(features, K.transpose(features))\n",
    "    return gram\n",
    "\n",
    "def style_loss(style, combination):\n",
    "    S = gram_matrix(style)\n",
    "    C = gram_matrix(combination)\n",
    "    channels = 3\n",
    "    size = img_height * img_width\n",
    "    return K.sum(K.square(S - C)) / (4. * (channels ** 2) * (size ** 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "anonymous-laundry",
   "metadata": {},
   "outputs": [],
   "source": [
    "def total_variation_loss(x):\n",
    "    a = K.square(x[:,:img_height - 1, :img_width - 1, :] - x[:, 1:, :img_width - 1, :])\n",
    "    b = K.square(x[:,:img_height - 1, :img_width - 1, :] - x[:, :img_height - 1, 1:, :])\n",
    "    return K.sum(K.pow(a + b, 1.25))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "orange-baghdad",
   "metadata": {},
   "outputs": [],
   "source": [
    "outputs_dict = dict([(layer.name, layer.output) for layer in model.layers])\n",
    "content_layer = 'block5_conv2'\n",
    "style_layers = ['block1_conv1',\n",
    "               'block2_conv1',\n",
    "               'block3_conv1',\n",
    "               'block4_conv1',\n",
    "               'block5_conv1']\n",
    "total_variation_weight = 1e-4\n",
    "style_weight = 1.\n",
    "content_weight = 0.025\n",
    "\n",
    "loss = K.variable(0.)\n",
    "layer_features = outputs_dict[content_layer]\n",
    "target_image_features = layer_features[0, :, :, :]\n",
    "combination_features = layer_features[2, :, :, :]\n",
    "loss = loss + content_weight * content_loss(target_image_features, combination_features)\n",
    "\n",
    "for layer_name in style_layers:\n",
    "    layer_features = outputs_dict[layer_name]\n",
    "    style_reference_features = layer_features[1, :, :, :]\n",
    "    combination_features = layer_features[2, :, :, :]\n",
    "    sl = style_loss(style_reference_features, combination_features)\n",
    "    loss += (style_weight / len(style_layers)) * sl\n",
    "    \n",
    "loss += total_variation_weight * total_variation_loss(combination_image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "finished-auditor",
   "metadata": {},
   "outputs": [],
   "source": [
    "grads = K.gradients(loss, combination_image)[0]\n",
    "\n",
    "fetch_loss_and_grads = K.function([combination_image], [loss, grads])\n",
    "\n",
    "class Evaluator(object):\n",
    "    \n",
    "    def __init__(self):\n",
    "        self.loss_value = None\n",
    "        self.grad_values = None\n",
    "        \n",
    "    def loss(self, x):\n",
    "        assert self.loss_value is None\n",
    "        x = x.reshape((1, img_height, img_width, 3))\n",
    "        outs = fetch_loss_and_grads([x])\n",
    "        loss_value = outs[0]\n",
    "        grad_values = outs[1].flatten().astype('float64')\n",
    "        self.loss_value = loss_value\n",
    "        self.grad_values = grad_values\n",
    "        return self.loss_value\n",
    "    \n",
    "    def grads(self, x):\n",
    "        assert self.loss_value is not None\n",
    "        grad_values = np.copy(self.grad_values)\n",
    "        self.loss_value = None\n",
    "        self.grad_values = None\n",
    "        return grad_values\n",
    "    \n",
    "evaluator = Evaluator()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "international-mexico",
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.optimize import fmin_l_bfgs_b\n",
    "#from scipy.misc import imsave\n",
    "from keras.preprocessing.image import save_img as imsave\n",
    "import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "turkish-penny",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Start of iteration  0\n",
      "Current loss value:  1386960500.0\n",
      "Image saved as  my_result_at_iteration_0.png\n",
      "Iteration 0 completed in 1830s \n",
      "Start of iteration  1\n",
      "Current loss value:  541376800.0\n",
      "Image saved as  my_result_at_iteration_1.png\n",
      "Iteration 1 completed in 1830s \n",
      "Start of iteration  2\n",
      "Current loss value:  342378270.0\n",
      "Image saved as  my_result_at_iteration_2.png\n",
      "Iteration 2 completed in 1786s \n",
      "Start of iteration  3\n",
      "Current loss value:  269283230.0\n",
      "Image saved as  my_result_at_iteration_3.png\n",
      "Iteration 3 completed in 1758s \n",
      "Start of iteration  4\n",
      "Current loss value:  221060530.0\n",
      "Image saved as  my_result_at_iteration_4.png\n",
      "Iteration 4 completed in 1753s \n",
      "Start of iteration  5\n"
     ]
    }
   ],
   "source": [
    "result_prefix = 'my_result'\n",
    "iterations = 20\n",
    "\n",
    "x = preprocess_image(target_image_path)\n",
    "x.flatten()\n",
    "for i in range(iterations):\n",
    "    print('Start of iteration ', i)\n",
    "    start_time = time.time()\n",
    "    x, min_val, info = fmin_l_bfgs_b(evaluator.loss, x, fprime=evaluator.grads, maxfun=20)\n",
    "    print('Current loss value: ', min_val)\n",
    "    img = x.copy().reshape((img_height, img_width, 3))\n",
    "    img = deprocess_image(img)\n",
    "    fname = result_prefix + '_at_iteration_%d.png' %i\n",
    "    imsave(fname, img)\n",
    "    print('Image saved as ', fname)\n",
    "    end_time = time.time()\n",
    "    print('Iteration %d completed in %ds ' % (i, end_time - start_time))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "conservative-individual",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
